package cn.zwk.drawing.infrastructure.execution;

import cn.zwk.drawing.domain.execution.model.ExecutionRequest;
import cn.zwk.drawing.domain.execution.model.ExecutionResult;
import cn.zwk.drawing.domain.execution.service.ExecutionDomainService;
import cn.zwk.drawing.domain.diagram.model.NodeCapability;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.scheduling.annotation.Async;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.*;

/**
 * 脚本执行服务实现
 */
@Slf4j
@Service
public class ScriptExecutionService implements ExecutionDomainService {

    private final ExecutorService executorService;
    private final Map<String, ExecutionResult> executionResults = new ConcurrentHashMap<>();
    private final Map<String, CompletableFuture<Void>> runningTasks = new ConcurrentHashMap<>();

    public ScriptExecutionService() {
        this.executorService = Executors.newFixedThreadPool(10);
    }

    @Override
    public ExecutionResult executeScript(ExecutionRequest request) {
        String executionId = request.getExecutionId();
        if (executionId == null) {
            executionId = UUID.randomUUID().toString();
            request.setExecutionId(executionId);
        }

        log.info("开始执行脚本: {} - {} -> {}", executionId, request.getNodeId(), request.getCapabilityId());

        ExecutionResult result = ExecutionResult.builder()
                .executionId(executionId)
                .nodeId(request.getNodeId())
                .capabilityId(request.getCapabilityId())
                .status(ExecutionResult.ExecutionStatus.RUNNING)
                .startedAt(LocalDateTime.now())
                .build();

        executionResults.put(executionId, result);

        try {
            // 模拟脚本执行
            String output = executeScriptInternal(request);

            result.setStatus(ExecutionResult.ExecutionStatus.SUCCESS);
            result.setOutput(output);
            result.setExitCode(0);
            result.setCompletedAt(LocalDateTime.now());
            result.setDuration(Duration.between(result.getStartedAt(), result.getCompletedAt()).toMillis());

            log.info("脚本执行成功: {} ({}ms)", executionId, result.getDuration());

        } catch (Exception e) {
            log.error("脚本执行失败: {}", executionId, e);

            result.setStatus(ExecutionResult.ExecutionStatus.FAILED);
            result.setErrorMessage(e.getMessage());
            result.setExitCode(1);
            result.setCompletedAt(LocalDateTime.now());
            result.setDuration(Duration.between(result.getStartedAt(), result.getCompletedAt()).toMillis());
        }

        return result;
    }

    @Override
    @Async
    public String executeScriptAsync(ExecutionRequest request) {
        String executionId = UUID.randomUUID().toString();
        request.setExecutionId(executionId);

        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            ExecutionResult result = executeScript(request);
            executionResults.put(executionId, result);
        }, executorService);

        runningTasks.put(executionId, future);

        // 清理任务
        future.whenComplete((v, t) -> runningTasks.remove(executionId));

        return executionId;
    }

    @Override
    public Optional<ExecutionResult> getExecutionResult(String executionId) {
        return Optional.ofNullable(executionResults.get(executionId));
    }

    @Override
    public boolean cancelExecution(String executionId) {
        CompletableFuture<Void> task = runningTasks.get(executionId);
        if (task != null && !task.isDone()) {
            boolean cancelled = task.cancel(true);
            if (cancelled) {
                ExecutionResult result = executionResults.get(executionId);
                if (result != null) {
                    result.setStatus(ExecutionResult.ExecutionStatus.CANCELLED);
                    result.setCompletedAt(LocalDateTime.now());
                }
                log.info("取消脚本执行: {}", executionId);
            }
            return cancelled;
        }
        return false;
    }

    @Override
    public List<ExecutionResult> getExecutionHistory(String nodeId, int limit) {
        return executionResults.values().stream()
                .filter(result -> nodeId.equals(result.getNodeId()))
                .filter(ExecutionResult::isCompleted)
                .sorted((a, b) -> b.getCompletedAt().compareTo(a.getCompletedAt()))
                .limit(limit)
                .toList();
    }

    @Override
    public boolean validateExecutionPermission(String userId, NodeCapability capability) {
        // 简化实现：检查能力的权限要求
        String requiredRole = capability.getRequiredRole();
        if (requiredRole == null) {
            return true; // 无权限要求
        }

        // 实际实现中应该查询用户角色
        return "admin".equals(userId) || "operator".equals(userId);
    }

    @Override
    public List<ExecutionResult> getRunningExecutions() {
        return executionResults.values().stream()
                .filter(result -> result.getStatus() == ExecutionResult.ExecutionStatus.RUNNING)
                .toList();
    }

    @Override
    public void cleanupCompletedExecutions() {
        LocalDateTime cutoff = LocalDateTime.now().minusHours(24);

        List<String> toRemove = executionResults.entrySet().stream()
                .filter(entry -> entry.getValue().isCompleted())
                .filter(entry -> entry.getValue().getCompletedAt().isBefore(cutoff))
                .map(Map.Entry::getKey)
                .toList();

        toRemove.forEach(executionResults::remove);
        log.info("清理已完成的执行记录: {} 条", toRemove.size());
    }

    @Override
    public ExecutionStatistics getExecutionStatistics() {
        List<ExecutionResult> results = new ArrayList<>(executionResults.values());

        long total = results.size();
        long successful = results.stream()
                .mapToLong(r -> r.isSuccess() ? 1 : 0)
                .sum();
        long failed = results.stream()
                .mapToLong(r -> r.getStatus() == ExecutionResult.ExecutionStatus.FAILED ? 1 : 0)
                .sum();
        long averageDuration = (long) results.stream()
                .filter(ExecutionResult::isCompleted)
                .mapToLong(r -> r.getDuration() != null ? r.getDuration() : 0)
                .average()
                .orElse(0.0);
        long running = runningTasks.size();

        return new ExecutionStatistics(total, successful, failed, averageDuration, running);
    }

    /**
     * 内部脚本执行逻辑
     */
    private String executeScriptInternal(ExecutionRequest request) throws Exception {
        String nodeId = request.getNodeId();
        String capabilityId = request.getCapabilityId();

        // 模拟不同类型的脚本执行
        return switch (nodeId + "_" + capabilityId) {
            case "api_health_check" -> generateHealthCheckOutput();
            case "api_view_logs" -> generateLogOutput();
            case "user_user_count" -> generateUserStatsOutput();
            case "order_order_count" -> generateOrderStatsOutput();
            case "db_db_status" -> generateDatabaseStatusOutput();
            case "cache_cache_status" -> generateCacheStatusOutput();
            default -> generateGenericOutput(nodeId, capabilityId);
        };
    }

    private String generateHealthCheckOutput() {
        return String.format("""
                === API Gateway 健康检查 ===
                检查时间: %s
                
                ✅ API Gateway 运行正常
                   - 服务端口: 8080
                   - 响应时间: %dms
                   - 内存使用: %dMB
                   - CPU使用率: %.1f%%
                   - 活跃连接: %d
                
                检查完成 ✅
                """,
                LocalDateTime.now(),
                15 + new Random().nextInt(20),
                480 + new Random().nextInt(100),
                2.0 + new Random().nextDouble() * 3,
                45 + new Random().nextInt(20)
        );
    }

    private String generateLogOutput() {
        LocalDateTime now = LocalDateTime.now();
        return String.format("""
                === API Gateway 最近日志 ===
                查询时间: %s
                
                [%s] INFO  - 接收到请求: GET /api/users
                [%s] INFO  - 转发请求到 User Service  
                [%s] INFO  - 接收到请求: POST /api/orders
                [%s] INFO  - 转发请求到 Order Service
                [%s] DEBUG - 健康检查通过
                
                日志查询完成 📋
                """,
                now,
                now.minusMinutes(1),
                now.minusSeconds(45),
                now.minusSeconds(30),
                now.minusSeconds(15),
                now.minusSeconds(5)
        );
    }

    private String generateUserStatsOutput() {
        Random random = new Random();
        return String.format("""
                === 用户服务统计信息 ===
                统计时间: %s
                
                📊 用户数据概览:
                   - 总用户数: %,d
                   - 活跃用户: %,d
                   - 新增用户(今日): %d
                   - 在线用户: %,d
                
                📈 用户增长趋势:
                   - 昨日: +%d 用户
                   - 本周: +%d 用户
                   - 本月: +%,d 用户
                
                统计完成 📊
                """,
                LocalDateTime.now(),
                15000 + random.nextInt(5000),
                8000 + random.nextInt(2000),
                100 + random.nextInt(50),
                1000 + random.nextInt(500),
                80 + random.nextInt(30),
                400 + random.nextInt(100),
                1800 + random.nextInt(300)
        );
    }

    private String generateOrderStatsOutput() {
        Random random = new Random();
        return String.format("""
                === 订单服务统计信息 ===
                统计时间: %s
                
                📦 订单数据概览:
                   - 总订单数: %,d
                   - 今日订单: %d
                   - 待处理: %d
                   - 已完成: %,d
                
                💰 收入统计:
                   - 今日收入: ¥%,d
                   - 本月收入: ¥%,d
                
                统计完成 📦
                """,
                LocalDateTime.now(),
                45000 + random.nextInt(5000),
                200 + random.nextInt(100),
                10 + random.nextInt(10),
                44000 + random.nextInt(1000),
                20000 + random.nextInt(10000),
                500000 + random.nextInt(100000)
        );
    }

    private String generateDatabaseStatusOutput() {
        Random random = new Random();
        return String.format("""
                === 数据库状态检查 ===
                检查时间: %s
                
                🔍 连接检查...
                ✅ 数据库连接正常
                   - 数据库类型: MySQL 8.0
                   - 连接数: %d/100
                   - 响应时间: %dms
                
                📊 性能指标:
                   - QPS: %,d
                   - TPS: %d
                   - 缓存命中率: %.1f%%
                   - 存储使用: %.1fGB/10GB
                
                检查完成 ✅
                """,
                LocalDateTime.now(),
                70 + random.nextInt(20),
                2 + random.nextInt(3),
                1200 + random.nextInt(300),
                500 + random.nextInt(200),
                95.0 + random.nextDouble() * 4,
                2.0 + random.nextDouble() * 2
        );
    }

    private String generateCacheStatusOutput() {
        Random random = new Random();
        return String.format("""
                === Redis缓存状态 ===
                检查时间: %s
                
                ⚡ 缓存服务正常
                   - 内存使用: %.1fGB/2GB
                   - 命中率: %.1f%%
                   - 键数量: %,d
                   - 连接数: %d
                
                📈 性能指标:
                   - 每秒操作数: %,d
                   - 平均响应时间: %.2fms
                   - 网络IO: %.1fMB/s
                
                检查完成 ⚡
                """,
                LocalDateTime.now(),
                1.0 + random.nextDouble() * 0.5,
                96.0 + random.nextDouble() * 3,
                150000 + random.nextInt(20000),
                15 + random.nextInt(10),
                5000 + random.nextInt(2000),
                0.1 + random.nextDouble() * 0.5,
                10.0 + random.nextDouble() * 20
        );
    }

    private String generateGenericOutput(String nodeId, String capabilityId) {
        return String.format("""
                === %s 执行结果 ===
                执行时间: %s
                节点: %s
                能力: %s
                
                ✅ 执行成功
                
                模拟执行完成
                """,
                capabilityId,
                LocalDateTime.now(),
                nodeId,
                capabilityId
        );
    }
}
